home *** CD-ROM | disk | FTP | other *** search
/ Explorer - Mosaic & Web / Explorer - Mosaic & Web.iso / helpers / ghostvew / src / gvwin.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-01  |  27.6 KB  |  916 lines

  1. /* Copyright (C) 1993, 1994, Russell Lang.  All rights reserved.
  2.   
  3.   This file is part of GSview.
  4.   
  5.   This program is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the GSview Free Public Licence 
  9.   (the "Licence") for full details.
  10.   
  11.   Every copy of GSview must include a copy of the Licence, normally in a 
  12.   plain ASCII text file named LICENCE.  The Licence grants you the right 
  13.   to copy, modify and redistribute GSview, but only under certain conditions 
  14.   described in the Licence.  Among other things, the Licence requires that 
  15.   the copyright notice and this notice be preserved on all copies.
  16. */
  17.  
  18. /* gvwin.c */
  19. /* Main routines for Windows GSview */
  20. /* by Russell Lang */
  21. #include "gvwin.h"
  22.  
  23. char szAppName[MAXSTR];            /* application name - for title bar */
  24. char szExePath[MAXSTR];
  25. char szIniFile[MAXSTR];
  26. char szWait[MAXSTR];
  27. char szFindText[MAXSTR];
  28. char previous_filename[MAXSTR];
  29. const char szClassName[] = "gsview_class";
  30. const char szScratch[] = "gsview";    /* temporary filename prefix */
  31.  
  32. HWND hwndimg;            /* gsview main window */
  33. HWND hDlgModeless;        /* any modeless dialog box */
  34. HWND hwndtext;            /* gswin text window */
  35. HWND hwndimgchild;        /* gswin image child window */
  36. HINSTANCE phInstance;        /* instance of gsview */
  37. int bitmap_scrollx=0;        /* offset from bitmap to origin of child window */
  38. int bitmap_scrolly=0;
  39. PSFILE psfile;        /* Postscript file structure */
  40. PROG gsprog;        /* Ghostscript program structure */
  41. OPTIONS option;        /* GSview options (saved in INI file) */
  42. DISPLAY display;    /* Display parameters */
  43. PSDOC *doc;
  44. struct page_list_s page_list;    /*  page selection for print/extract */
  45.  
  46.  
  47. struct sound_s sound[NUMSOUND] = {
  48.     {"SoundOutputPage", IDS_SNDPAGE, ""},
  49.     {"SoundNoPage", IDS_SNDNOPAGE, BEEP},
  50.     {"SoundNoNumbering", IDS_SNDNONUMBER, ""},
  51.     {"SoundNotOpen", IDS_SNDNOTOPEN, ""},
  52.     {"SoundError", IDS_SNDERROR, BEEP},
  53.     {"SoundTimeout", IDS_SNDTIMEOUT, ""},
  54.     {"SoundStart", IDS_SNDSTART, ""},
  55.     {"SoundExit", IDS_SNDEXIT, ""},
  56. };
  57.  
  58. /* initialised in init.c */
  59. BOOL is_win31 = FALSE;        /* To allow selective use of win 3.1 features */
  60. char szHelpName[MAXSTR];    /* buffer for building help filename */
  61. char szHelpTopic[MAXSTR];    /* topic for OFN_SHOWHELP */
  62. UINT help_message;        /* message sent by OFN_SHOWHELP */
  63. HMENU hmenu;            /* main menu */
  64. HACCEL haccel;            /* menu accelerators */
  65. HCURSOR hcWait;
  66. POINT img_offset;        /* offset to gswin child window */
  67. POINT info_file;        /* position of file information */
  68. POINT info_page;        /* position of page information */
  69. RECT  info_rect;        /* position and size of brief info area */
  70. RECT  info_coord;        /* position and size of coordinate information */
  71. RECT  button_rect;        /* position and size of button area */
  72.  
  73. BOOL prev_in_child;        /* true if cursor previously in gswin child window */
  74. BOOL waiting = FALSE;        /* true when 'wait' to be displayed in info area */
  75. int page_extra;            /* extra pages to skip */
  76. int page_skip = 5;        /* number of pages to skip in IDM_NEXTSKIP or IDM_PREVSKIP */
  77. BOOL changed_version = FALSE;    /* to warn user to update Ghostscript Command */
  78. BOOL zoom = FALSE;        /* true if display zoomed */
  79. BOOL debug = FALSE;        /* /D command line option used */
  80. HINSTANCE hlib_mmsystem;    /* DLL containing sndPlaySound function */
  81. FPSPS lpfnSndPlaySound;        /* pointer to sndPlaySound function if loaded */
  82.  
  83. /* timer used for open, close, display & print timeouts */
  84. BOOL bTimeout;            /* true if timeout occured */
  85. BOOL bTimerSet;            /* true if TIMER running */
  86. #define ID_MYTIMER 1
  87. UINT timeout_count;
  88.  
  89. /* document manipulation */
  90.  
  91. /* local functions */
  92. BOOL draw_button(DRAWITEMSTRUCT FAR *lpdis);
  93. BOOL in_child_client_area(void);
  94. BOOL in_client_area(void);
  95. BOOL in_info_area(void);
  96. void info_paint(HWND, HDC);
  97. void cursorpos_paint(HDC hdc);
  98. void gsview_close(void);
  99.  
  100.  
  101. int PASCAL 
  102. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int cmdShow)
  103. {
  104.     MSG msg;
  105.  
  106.     /* copy the hInstance into a variable so it can be used */
  107.     phInstance = hInstance;
  108.  
  109.     LoadString(hInstance, IDS_TITLE, szAppName, sizeof(szAppName));
  110.     if (hPrevInstance) {
  111.         /* don't run more than one copy */
  112.         /* because we can't run more than one Ghostscript */
  113.         gsview_init0(lpszCmdLine);
  114.         return FALSE;
  115.     }
  116.  
  117.     gsview_init1(lpszCmdLine);
  118.     ShowWindow(hwndimg, cmdShow);
  119.     
  120.     while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
  121.         if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  122.             if (!TranslateAccelerator(hwndimg, haccel, &msg)) {
  123.             TranslateMessage(&msg);
  124.             DispatchMessage(&msg);
  125.             }
  126.         }
  127.     }
  128.  
  129.     play_sound(SOUND_EXIT);
  130.     gsview_close();
  131.      WinHelp(hwndimg,szHelpName,HELP_QUIT,(DWORD)NULL);
  132.     if (is_win31 && (hlib_mmsystem != (HINSTANCE)NULL))
  133.         FreeLibrary(hlib_mmsystem);
  134.     return 0;
  135. }
  136.  
  137.  
  138. /* parent overlapped window */
  139. LRESULT CALLBACK _export
  140. WndImgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  141. {
  142. RECT rect;
  143.  
  144.     if (message == WM_GSVIEW) {
  145.     switch(wParam) {
  146.         case HWND_TEXT:
  147.         /* lParam = handle to Ghostscript Borland EasyWin window */
  148.         hwndtext = (HWND)lParam;
  149.         break;
  150.         case HWND_IMGCHILD:
  151.         /* lParam = handle to Ghostscript image child window */
  152.         hwndimgchild = (HWND)lParam;
  153.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  154.             SetClassCursor(hwndimgchild, LoadCursor((HINSTANCE)NULL, IDC_CROSS));
  155.             GetClientRect(hwnd, &rect);
  156.             SetWindowPos(hwndimgchild, (HWND)NULL, rect.left+img_offset.x, rect.top+img_offset.y,
  157.             rect.right-img_offset.x, rect.bottom-img_offset.y, 
  158.             SWP_NOZORDER | SWP_NOACTIVATE);
  159.         }
  160.         break;
  161.         case GSWIN_CLOSE:
  162.         /* something is closing gswin */
  163.         gsprog.hinst = (HINSTANCE)NULL;
  164.         gsprog.valid = FALSE;
  165.         hwndimgchild = (HWND)NULL;
  166.         hwndtext = (HWND)NULL;
  167.         bitmap_scrollx = bitmap_scrolly = 0;
  168.         display.page = FALSE;
  169.         display.saved = FALSE;
  170.         page_extra = 0;
  171.         pipeclose();
  172.         clear_timer();
  173.         info_wait(FALSE);
  174.         break;
  175.         case OUTPUT_PAGE:
  176.         /* showpage has just been called */
  177.         clear_timer();
  178.         play_sound(SOUND_PAGE);
  179.         if (IsIconic(hwndimg))    /* useless as an Icon so fix it */
  180.             ShowWindow(hwndimg, SW_SHOWNORMAL);
  181.         if ( !IsIconic(hwndimg) ) {  /* redraw child window */
  182.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  183.             /* don't erase background - the bitmap will cover it anyway */
  184.             InvalidateRect(hwndimgchild, (LPRECT)NULL, FALSE);
  185.             UpdateWindow(hwndimgchild);
  186.             }
  187.         }
  188.         display.page = TRUE;
  189.         info_wait(FALSE);
  190.         if (page_extra) {
  191.             PostMessage(hwndimg, WM_COMMAND, IDM_SKIP, (LPARAM)0);
  192.         }
  193.         break;
  194.         case SYNC_OUTPUT:
  195.         /* time to redraw window */
  196.         if ( !IsIconic(hwndimg) ) {  /* redraw child window */
  197.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  198.             /* don't erase background - the bitmap will cover it anyway */
  199.             InvalidateRect(hwndimgchild, (LPRECT)NULL, FALSE);
  200.             UpdateWindow(hwndimgchild);
  201.             }
  202.         }
  203.         break;
  204.         case SCROLL_POSITION:
  205.         /* User scrolled image window.  
  206.          * lParam = offsets to top left of image window
  207.          * we use these to display coordinates */
  208.         bitmap_scrollx = LOWORD(lParam);
  209.         bitmap_scrolly = HIWORD(lParam);
  210.         InvalidateRect(hwndimg, &info_coord, FALSE);
  211.         UpdateWindow(hwndimg);
  212.         break;
  213.         case PIPE_REQUEST:
  214.         load_string(IDS_WAITDRAW, szWait, sizeof(szWait));
  215.         info_wait(TRUE);
  216.         piperequest();
  217.         break;
  218.         case BEGIN:
  219.         case END:
  220.         /* do nothing at present */
  221.         /* we can figure out when we have reached EOF by inspecting */
  222.         /* the imitation pipe */
  223.         break;
  224.         default:
  225.         gserror(0, "Unknown Message", MB_ICONEXCLAMATION, -1);
  226.     }
  227.     return 0;
  228.     }
  229.     else if (message == help_message) {
  230.     WinHelp(hwndimg,szHelpName,HELP_KEY,(DWORD)szHelpTopic);
  231.     return 0;
  232.     } else
  233.     switch(message) {
  234.     case WM_CREATE:
  235.         hwndimg = hwnd;
  236.         gsview_create();
  237.         /* Enable Drag Drop */
  238.         if (is_win31)
  239.             DragAcceptFiles(hwnd, TRUE);
  240.         break;
  241.     case WM_DESTROY:
  242.         /* disable Drag Drop */
  243.         if (is_win31)
  244.             DragAcceptFiles(hwnd, FALSE);
  245.         gsview_close();
  246.         PostQuitMessage(0);
  247.         break;
  248.     case WM_ENDSESSION:
  249.         if (wParam)
  250.             gsview_close();
  251.         return 0;
  252.     case WM_TIMER:
  253.         if (wParam == ID_MYTIMER) {
  254.             timeout_count--;
  255.             if (timeout_count <= 0) {
  256.             clear_timer();
  257.             bTimeout = TRUE;
  258.             gserror(IDS_TIMEOUT, NULL, MB_ICONINFORMATION, SOUND_TIMEOUT);
  259.             info_wait(FALSE);
  260.             }
  261.         }
  262.         break;
  263.     case WM_DROPFILES:
  264.         if (is_win31) {
  265.             LPSTR szFile;
  266.                 HGLOBAL hglobal;
  267.             int i, cFiles, length;
  268.             HDROP hdrop = (HDROP)wParam;
  269.             cFiles = DragQueryFile(hdrop, 0xffff, (LPSTR)NULL, 0);
  270.             for (i=0; i<cFiles; i++) {
  271.             length = DragQueryFile(hdrop, i, (LPSTR)NULL, 0);
  272.                 hglobal = GlobalAlloc(GHND | GMEM_SHARE, length+1);
  273.             if (hglobal) {
  274.                 szFile = GlobalLock(hglobal);
  275.                 DragQueryFile(hdrop, i, szFile, MAXSTR);
  276.                     GlobalUnlock(hglobal);
  277.                 /* it doesn't work if we call gsview_display directly */
  278.                 PostMessage(hwnd, WM_COMMAND, IDM_DROP, (LPARAM)hglobal);
  279.             }
  280.             }
  281.             DragFinish(hdrop);
  282.         }
  283.         break;
  284.     case WM_INITMENU:
  285.         if (hmenu == (HMENU)wParam) {
  286.             HMENU hmenuedit = GetSubMenu(hmenu,1);
  287.             if (hwndimgchild  && IsWindow(hwndimgchild))
  288.             EnableMenuItem(hmenu, IDM_COPYCLIP, MF_ENABLED);
  289.             else
  290.             EnableMenuItem(hmenu, IDM_COPYCLIP, MF_DISABLED | MF_GRAYED);
  291.             if (OpenClipboard(hwnd)) {
  292.             if (IsClipboardFormatAvailable(CF_DIB))
  293.                 EnableMenuItem(hmenu, IDM_PASTETO, MF_ENABLED);
  294.             else
  295.                 EnableMenuItem(hmenu, IDM_PASTETO, MF_DISABLED | MF_GRAYED);
  296.             if (IsClipboardFormatAvailable(CF_DIB) || 
  297.                 IsClipboardFormatAvailable(CF_BITMAP)) 
  298.                 EnableMenuItem(hmenu, IDM_CONVERT, MF_ENABLED);
  299.             else
  300.                 EnableMenuItem(hmenu, IDM_CONVERT, MF_DISABLED | MF_GRAYED);
  301.             /* Make EPS sub menu */
  302.             if ((IsClipboardFormatAvailable(CF_DIB) ||
  303.                  IsClipboardFormatAvailable(CF_BITMAP)) 
  304.                 && (doc != (PSDOC *)NULL) && doc->epsf)
  305.                 EnableMenuItem(hmenuedit, 5, MF_BYPOSITION | MF_ENABLED);
  306.             else
  307.                 EnableMenuItem(hmenuedit, 5, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  308.             /* Extract EPS sub menu */
  309.             if ( (psfile.preview == IDS_EPST) || (psfile.preview == IDS_EPSW) )
  310.                 EnableMenuItem(hmenuedit, 6, MF_BYPOSITION | MF_ENABLED);
  311.             else
  312.                 EnableMenuItem(hmenuedit, 6, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
  313.             CloseClipboard();
  314.             }
  315.             return 0;
  316.         }
  317.         break;
  318.     case WM_COMMAND:
  319.         if (LOWORD(wParam) == IDM_DROP) {
  320.             LPSTR szFile;
  321.             char cmd[MAXSTR];
  322.             szFile = GlobalLock((HGLOBAL)lParam);
  323.             if (szFile && (lstrlen(szFile) < sizeof(cmd)))
  324.             lstrcpy(cmd, szFile);
  325.             else
  326.             cmd[0] = '\0';
  327. #ifdef NOTUSED
  328. #ifdef __WIN32__
  329.             hglobal = GlobalHandle((LPCVOID)lParam);
  330. #else
  331.             hglobal = (HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lParam)));
  332. #endif
  333. #endif
  334.             GlobalUnlock((HGLOBAL)lParam);
  335.             GlobalFree((HGLOBAL)lParam);
  336.             if ((cmd[0] == '-') || (cmd[0] == '/')) {
  337.             switch (toupper(cmd[1])) {
  338.                 case 'P':
  339.                       gsview_selectfile(cmd+2);
  340.                       gsview_print(FALSE);
  341.                   break;
  342.                 case 'F':
  343.                       gsview_selectfile(cmd+2);
  344.                       gsview_print(TRUE);
  345.                   break;
  346.                 case 'S':
  347.                   if (cmd[2] != ' ') {
  348.                 char *fname;
  349.                 /* skip over port name */
  350.                 for (fname=cmd+2; *fname && *fname!=' '; fname++)
  351.                   /* nothing */ ;
  352.                     /* skip blanks until file name */
  353.                     if (*fname) {
  354.                       *fname++ = '\0'; /* place null after port name */
  355.                       for (; *fname==' '; fname++)
  356.                         /* nothing */ ;
  357.                     }
  358.                     if (*fname) {
  359.                         /* found both filename and port */
  360.                         gsview_spool(fname, cmd+2);
  361.                         break;
  362.                     }
  363.                   }
  364.                       gsview_spool(cmd+2, (char *)NULL);
  365.                   break;
  366.                 default:
  367.                   gserror(IDS_BADCLI, cmd, MB_ICONEXCLAMATION, SOUND_ERROR);
  368.             }
  369.             }
  370.             else
  371.                 gsview_displayfile(cmd);
  372.         }
  373.         else {
  374.             if (GetNotification(wParam,lParam) != BN_DOUBLECLICKED) {
  375.             if (hDlgModeless) {
  376.                 play_sound(SOUND_ERROR);
  377.                 return 0;    /* obtaining Bounding Box so ignore commands */
  378.             }
  379.             if (waiting) {
  380.                 switch(LOWORD(wParam)) {
  381.                         case IDM_INFO:
  382.                         case IDM_SAVEDIR:
  383.                         case IDM_SETTINGS:
  384.                         case IDM_SAVESETTINGS:
  385.                         case IDM_SOUNDS:
  386.                         case IDM_HELPCONTENT:
  387.                         case IDM_HELPSEARCH:
  388.                         case IDM_ABOUT:
  389.                 case IDM_EXIT:
  390.                     /* these are safe to use when busy */
  391.                     break;
  392.                     default:
  393.                         play_sound(SOUND_ERROR);
  394.                         return 0;    /* Command not permitted now */
  395.                 }
  396.             }
  397.                 gsview_command(LOWORD(wParam));
  398.             }
  399.         }
  400.         /* if command resulted in an update to the display, do it */
  401.         if (display.do_endfile || display.do_resize || display.do_display) {
  402.             if (!gs_open())
  403.             return FALSE;
  404.             dfreopen();
  405.             do_output();
  406.             fflush(gsprog.input);
  407.             dfclose();
  408.             pipeflush();
  409.             display.busy = FALSE;
  410.             display.abort = FALSE;
  411.             display.do_endfile = FALSE;
  412.             display.do_resize = FALSE;
  413.             display.do_display = FALSE;
  414.         }
  415.         return 0;
  416.     case WM_KEYDOWN:
  417.     case WM_KEYUP:
  418.         /* pass on key presses so that child window scroll bars work */
  419.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  420.             SendMessage(hwndimgchild, message, wParam, lParam);
  421.             return 0;
  422.         }
  423.         break;
  424.     case WM_SIZE:
  425.         /* make child window fill client area */
  426.         if (wParam != SIZE_MINIMIZED  && hwndimgchild !=(HWND)NULL && IsWindow(hwndimgchild))
  427.             SetWindowPos(hwndimgchild, (HWND)NULL, img_offset.x, img_offset.y,
  428.             LOWORD(lParam)-img_offset.x, HIWORD(lParam)-img_offset.y, 
  429.             SWP_NOZORDER | SWP_NOACTIVATE);
  430.         /* save window size for INIFILE */
  431.         if (wParam == SIZE_RESTORED) {
  432.             GetWindowRect(hwnd,&rect);
  433.             option.img_size.x = rect.right-rect.left;
  434.             option.img_size.y = rect.bottom-rect.top;
  435.         }
  436.         return 0;
  437.     case WM_MOVE:
  438.         /* save window position for INIFILE */
  439.         if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
  440.             GetWindowRect(hwnd,&rect);
  441.             option.img_origin.x = rect.left;
  442.             option.img_origin.y = rect.top;
  443.         }
  444.         return 0;
  445.     case WM_SETCURSOR:
  446.         /* if waiting, display hourglass cursor over our window */
  447.         if (waiting) {
  448.             if (hwndimgchild && IsWindow(hwndimgchild)) {
  449.             if (in_child_client_area() || in_info_area() || (LOWORD(lParam)==HTMENU)) {
  450.                 SetCursor(hcWait);
  451.                 return TRUE;
  452.                 }
  453.             }
  454.             else {
  455.                 SetCursor(hcWait);
  456.                 return TRUE;
  457.             }
  458.         }
  459.         /* track cursor and display coordinates if in child window */
  460.         if (hwndimgchild && IsWindow(hwndimgchild)) {
  461.             if (in_child_client_area() || prev_in_child) {
  462.             /* update coordinate info */
  463.             HDC hdc;
  464.             hdc = GetDC(hwnd);
  465.             cursorpos_paint(hdc);
  466.             ReleaseDC(hwnd, hdc);
  467.             }
  468.             prev_in_child = in_child_client_area();
  469.         }
  470.         break;
  471.     case WM_PARENTNOTIFY:
  472.         if (hDlgModeless && (wParam == WM_LBUTTONDOWN))
  473.             if (in_child_client_area())
  474.                 SendMessage(hDlgModeless, WM_COMMAND, BB_CLICK, lParam);
  475.         if (wParam == WM_RBUTTONDOWN) {
  476.             float x, y;
  477.             RECT rect;
  478.             GetWindowRect(hwndimgchild,&rect);
  479.             if (get_cursorpos(&x, &y)) {
  480.                 zoom = !zoom;
  481.                 display.zoom_xoffset = x;
  482.                 display.zoom_yoffset = y;
  483.             x = (bitmap_scrollx + (rect.right - rect.left)/2)*72.0/option.xdpi;
  484.             y = ((display.height-1) - (bitmap_scrolly + (rect.bottom - rect.top)/2))*72.0/option.ydpi;
  485.             transform_cursorpos(&x, &y);
  486.             x *= option.xdpi/72.0;
  487.             y *= option.ydpi/72.0;
  488.             display.zoom_xoffset -= (int)(x*72.0/option.zoom_xdpi);
  489.             display.zoom_yoffset -= (int)(y*72.0/option.zoom_ydpi);
  490.             }
  491.             else {
  492.                 zoom = FALSE;
  493.             }
  494.             PostMessage(hwndimg, WM_COMMAND, IDM_ZOOM, (LPARAM)0);
  495.         }
  496.         break;
  497.     case WM_PAINT:
  498.         {
  499.         HDC hdc;
  500.         PAINTSTRUCT ps;
  501.         RECT chrect;
  502.         hdc = BeginPaint(hwnd, &ps);
  503.         /* draw info area at top */
  504.         info_paint(hwnd, hdc);
  505.         /* draw button background */
  506.         if (button_rect.right) {
  507.             GetClientRect(hwnd, &rect);
  508.             rect.top = button_rect.top;
  509.             rect.left = button_rect.left;
  510.             rect.right = button_rect.right;
  511.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  512.             SelectPen(hdc, GetStockObject(BLACK_PEN));
  513.             MoveTo(hdc, rect.right, rect.top);
  514.             LineTo(hdc, rect.right, rect.bottom);
  515.         }
  516.         /* fill area outside Ghostscript image client */
  517.         if (!option.fit_page && hwndimgchild && IsWindow(hwndimgchild)) {
  518.             GetClientRect(hwnd, &rect);
  519.             GetWindowRect(hwndimgchild, &chrect);
  520.             rect.top = info_rect.bottom+1;
  521.             rect.left = img_offset.x + chrect.right - chrect.left;
  522.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  523.             rect.left = button_rect.right+1;
  524.             rect.top = img_offset.y + chrect.bottom - chrect.top;
  525.             FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  526.         }
  527.         EndPaint(hwnd, &ps);
  528.         }
  529.         return 0;
  530.     case WM_MEASUREITEM:
  531.         return 1;
  532.     case WM_DRAWITEM:
  533.         return draw_button((DRAWITEMSTRUCT FAR *)lParam);
  534.     }
  535.     return DefWindowProc(hwnd, message, wParam, lParam);
  536. }
  537.  
  538. /* return TRUE if button drawn */
  539. BOOL
  540. draw_button(DRAWITEMSTRUCT FAR *lpdis)
  541. {
  542. HBRUSH hbrush;
  543. HPEN hpen_highlight, hpen_shadow, hpen_old;
  544. HDC hdc = lpdis->hDC;
  545. RECT rect;
  546. HICON hicon;
  547. HBITMAP hbitmap_old, hbitmap;
  548. BITMAP bm;
  549. int i;
  550. char buf[20];
  551.     rect = lpdis->rcItem;
  552.     if (lpdis->CtlType != ODT_BUTTON)
  553.         return FALSE;
  554.     switch (lpdis->itemAction) {
  555.         case ODA_DRAWENTIRE:
  556.         if ((hbitmap = LoadBitmap(phInstance,MAKEINTRESOURCE(lpdis->CtlID)))
  557.           != (HBITMAP)NULL) {
  558.             HDC hdcsrc = CreateCompatibleDC(hdc);
  559.             hbitmap_old = SelectObject(hdcsrc,hbitmap);
  560.             GetObject(hbitmap, sizeof(BITMAP),&bm);
  561.             if ( (rect.right-rect.left > bm.bmWidth) ||
  562.              (rect.bottom-rect.top > bm.bmHeight) ) {
  563.                 hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  564.                 FillRect(hdc, &rect, hbrush);
  565.                 DeleteBrush(hbrush);
  566.             }
  567.             BitBlt(hdc, (rect.left+rect.right-bm.bmWidth)/2,
  568.                (rect.top+rect.bottom-bm.bmHeight)/2,
  569.                bm.bmWidth,bm.bmHeight,hdcsrc,0,0,SRCCOPY);
  570.             SelectObject(hdcsrc,hbitmap_old);
  571.             DeleteObject(hbitmap);
  572.             DeleteDC(hdcsrc);
  573.         }
  574.         else {
  575.             hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  576.             FillRect(hdc, &rect, hbrush);
  577.             DeleteBrush(hbrush);
  578.             if ((i = LoadString(phInstance, lpdis->CtlID, buf, sizeof(buf)))
  579.                 != 0) {
  580. #ifdef __WIN32__
  581.             SIZE sz;
  582.             GetTextExtentPoint(hdc, buf, i, &sz);
  583.             SetBkMode(hdc, TRANSPARENT);
  584.             TextOut(hdc, (rect.left+rect.right-sz.cx)/2,
  585.                 (rect.top+rect.bottom-sz.cy)/2, buf, i);
  586. #else
  587.             DWORD dw = GetTextExtent(hdc, buf, i);
  588.             SetBkMode(hdc, TRANSPARENT);
  589.             TextOut(hdc, (rect.left+rect.right-LOWORD(dw))/2,
  590.                 (rect.top+rect.bottom-HIWORD(dw))/2, buf, i);
  591. #endif
  592.             }
  593.             else if ( (hicon = LoadIcon(phInstance, MAKEINTRESOURCE(lpdis->CtlID)))
  594.                 != (HICON)NULL )  {
  595.                 DrawIcon(hdc, (rect.left+rect.right-32)/2, 
  596.                     (rect.top+rect.bottom-32)/2, hicon);
  597.                 DestroyIcon(hicon);
  598.             }
  599.         }
  600.         hpen_old = SelectPen(hdc, GetStockObject(BLACK_PEN));
  601.         MoveTo(hdc, rect.left, rect.top);
  602.         LineTo(hdc, rect.right-1, rect.top);
  603.         LineTo(hdc, rect.right-1, rect.bottom-1);
  604.         LineTo(hdc, rect.left, rect.bottom-1);
  605.         LineTo(hdc, rect.left, rect.top-1);
  606.         SelectPen(hdc, hpen_old);
  607.         /* fall thru */
  608.         case ODA_FOCUS:
  609.         case ODA_SELECT:
  610.         if (lpdis->itemState & ODS_SELECTED) {
  611.             hpen_highlight = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  612.             hpen_shadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNFACE));
  613.         }
  614.         else {
  615.             hpen_highlight = CreatePen(PS_SOLID, 1, is_win31 ? GetSysColor(COLOR_BTNHIGHLIGHT) : RGB(255,255,255));
  616.             hpen_shadow = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
  617.         }
  618.         hpen_old = SelectPen(hdc, hpen_highlight);
  619.         MoveTo(hdc, rect.left+1, rect.bottom-3);
  620.         LineTo(hdc, rect.left+1, rect.top+1);
  621.         LineTo(hdc, rect.right-2, rect.top+1);
  622.         MoveTo(hdc, rect.right-3, rect.top+2);
  623.         LineTo(hdc, rect.left+2, rect.top+2);
  624.         LineTo(hdc, rect.left+2, rect.bottom-4);
  625.         SelectPen(hdc, hpen_shadow);
  626.         MoveTo(hdc, rect.left+1, rect.bottom-2);
  627.         LineTo(hdc, rect.right-2, rect.bottom-2);
  628.         LineTo(hdc, rect.right-2, rect.top+1);
  629.         MoveTo(hdc, rect.right-3, rect.top+2);
  630.         LineTo(hdc, rect.right-3, rect.bottom-3);
  631.         LineTo(hdc, rect.left+2, rect.bottom-3);
  632.         SelectPen(hdc, hpen_old);
  633.         DeleteObject(hpen_highlight);
  634.         DeleteObject(hpen_shadow);
  635.             return TRUE;
  636.     }
  637.     return FALSE;
  638. }
  639.  
  640. /* returns true if cursor in client area of Ghostscript image window */
  641. BOOL
  642. in_child_client_area()
  643. {
  644. RECT rect;
  645. POINT pt;
  646. HWND hwnd;
  647.         GetCursorPos(&pt);
  648.     hwnd = WindowFromPoint(pt);
  649.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  650.         return 0;
  651.         GetClientRect(hwndimgchild, &rect);
  652.         ScreenToClient(hwndimgchild, &pt);
  653.         return PtInRect(&rect, pt);
  654. }
  655.  
  656. /* returns true if cursor in client area of GSview window */
  657. BOOL
  658. in_client_area()
  659. {
  660. RECT rect;
  661. POINT pt;
  662. HWND hwnd;
  663.         GetCursorPos(&pt);
  664.     hwnd = WindowFromPoint(pt);
  665.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  666.         return 0;
  667.         GetClientRect(hwndimg, &rect);
  668.         ScreenToClient(hwndimg, &pt);
  669.         return PtInRect(&rect, pt);
  670. }
  671.  
  672. /* returns true if cursor in info area or button area of GSview windows */
  673. BOOL
  674. in_info_area()
  675. {
  676. RECT rect;
  677. POINT pt;
  678. HWND hwnd;
  679.         GetCursorPos(&pt);
  680.     hwnd = WindowFromPoint(pt);
  681.     if ((hwnd != hwndimg) && !IsChild(hwndimg,hwnd))
  682.         return 0;
  683.         ScreenToClient(hwndimg, &pt);
  684.  
  685.         GetClientRect(hwndimg, &rect);
  686.     rect.bottom = img_offset.y;
  687.     if (PtInRect(&rect, pt))
  688.         return TRUE;
  689.         GetClientRect(hwndimg, &rect);
  690.     rect.right = img_offset.x;
  691.         return PtInRect(&rect, pt);
  692. }
  693.  
  694. BOOL
  695. get_cursorpos(float *x, float *y)
  696. {
  697. RECT rect;
  698. POINT pt;
  699.     if (hwndimgchild && IsWindow(hwndimgchild)) {
  700.     GetClientRect(hwndimgchild, &rect);
  701.     GetCursorPos(&pt);
  702.     ScreenToClient(hwndimgchild, &pt);
  703.     if (PtInRect(&rect, pt)) {
  704.       if (zoom) {
  705.             /* first figure out number of pixels to zoom origin point */
  706.         *x = (bitmap_scrollx+pt.x)*72.0/option.xdpi;
  707.         *y = ((display.height-1) -(bitmap_scrolly+pt.y))*72.0/option.ydpi;
  708.         transform_cursorpos(x,y);
  709.         *x = *x * option.xdpi/72;
  710.         *y = *y * option.ydpi/72;
  711.         /* now convert to pts and offset it */
  712.         *x = *x * 72/option.zoom_xdpi + display.zoom_xoffset;
  713.         *y = *y * 72/option.zoom_ydpi + display.zoom_yoffset;
  714.       }
  715.       else {
  716.         *x = (bitmap_scrollx+pt.x)*72.0/option.xdpi 
  717.         + (display.epsf_clipped ? doc->bbox.llx : 0);
  718.         *y = ((display.height-1)-(bitmap_scrolly+pt.y))*72.0/option.ydpi
  719.         + (display.epsf_clipped ? doc->bbox.lly : 0);
  720.         transform_cursorpos(x,y);
  721.       }
  722.         return TRUE;
  723.     }
  724.     }
  725.     return FALSE;
  726. }
  727.  
  728. void
  729. cursorpos_paint(HDC hdc)
  730. {
  731. float x, y;
  732. char buf[32];
  733.     SetBkMode(hdc, TRANSPARENT);
  734.         FillRect(hdc, &info_coord, GetStockObject(LTGRAY_BRUSH));
  735.     /* show coordinate */
  736.     if (get_cursorpos(&x, &y)) {
  737.         switch(option.unit) {
  738.            case IDM_UNITPT:   
  739.           sprintf(buf,"%.0f, %.0fpt", x, y);
  740.           break;
  741.            case IDM_UNITMM:   
  742.           sprintf(buf,"%.0f, %.0fmm", x/72*25.4, y/72*25.4);
  743.           break;
  744.            case IDM_UNITINCH:   
  745.           sprintf(buf,"%.1f, %.1fin", x/72, y/72);
  746.           break;
  747.         }
  748.         SetTextAlign(hdc, TA_RIGHT);
  749.         TextOut(hdc, info_coord.right-1, info_coord.top, buf, strlen(buf));
  750.     }
  751. }
  752.  
  753. /* paint brief info area */
  754. void
  755. info_paint(HWND hwnd, HDC hdc)
  756. {
  757. RECT rect;
  758. int i;
  759. char buf[MAXSTR];
  760. char fmt[MAXSTR];
  761.     SetBkMode(hdc, TRANSPARENT);
  762.     if (info_rect.bottom) {
  763.         GetClientRect(hwnd, &rect);
  764.         rect.top = 0;
  765.         rect.left = info_rect.left;
  766.         rect.bottom = info_rect.bottom;
  767.         FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  768.         SelectPen(hdc, GetStockObject(BLACK_PEN));
  769.         MoveTo(hdc, rect.left, rect.bottom);
  770.         LineTo(hdc, rect.right, rect.bottom);
  771.     }
  772.     /* write file information */
  773.     if (psfile.name[0] != '\0') {
  774.         i = LoadString(phInstance, IDS_FILE, buf, sizeof(buf));
  775.         GetFileTitle(psfile.name, buf+i, (WORD)(sizeof(buf)-i));
  776.         TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  777.         if (waiting) {
  778.         TextOut(hdc, info_page.x, info_page.y, szWait, strlen(szWait));
  779.         }
  780.         else {
  781.           if (doc!=(PSDOC *)NULL) {
  782.         int n = map_page(psfile.pagenum - 1);
  783.         i = LoadString(phInstance, IDS_PAGEINFO, fmt, sizeof(fmt));
  784.         if (doc->pages)
  785.             sprintf(buf, fmt, doc->pages[n].label ? doc->pages[n].label : " ",psfile.pagenum,  doc->numpages);
  786.         else
  787.             sprintf(buf, fmt, " " ,psfile.pagenum,  doc->numpages);
  788.         if (zoom)
  789.             strcat(buf, "  Zoomed");
  790.         TextOut(hdc, info_page.x, info_page.y, buf, strlen(buf));
  791.           }
  792.           else {
  793.         if (is_pipe_done())
  794.             i = LoadString(phInstance, IDS_NOMORE, buf, sizeof(buf));
  795.         else {
  796.             i = LoadString(phInstance, IDS_PAGE, buf, sizeof(buf));
  797.             sprintf(buf+i, "%d", psfile.pagenum);
  798.         }
  799.         TextOut(hdc, info_page.x, info_page.y, buf, strlen(buf));
  800.           }
  801.           /* show coordinate */
  802.           cursorpos_paint(hdc);
  803.         }
  804.     }
  805.     else {
  806.         i = LoadString(phInstance, IDS_NOFILE, buf, sizeof(buf));
  807.         TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  808.         if (waiting) {
  809.         TextOut(hdc, info_page.x, info_page.y, szWait, strlen(szWait));
  810.         }
  811.     }
  812. }
  813.  
  814.  
  815. HWND hbutton_info;
  816.  
  817. /* subclass button WndProc to give focus back to parent window */
  818. LRESULT CALLBACK _export
  819. MenuButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  820. {
  821.     switch(message) {
  822.         case WM_LBUTTONUP:
  823.         {
  824.         RECT rect;
  825.         POINT pt;
  826.         GetWindowRect(hwnd, &rect);
  827.         GetCursorPos(&pt);
  828.         if (PtInRect(&rect, pt))
  829.             SendMessage(GetParent(hwnd), WM_COMMAND, GetWindowID(hwnd), 0L);
  830.         SetFocus(GetParent(hwnd));
  831.         }
  832.         break;
  833. #ifdef NOTUSED
  834.     case WM_SETCURSOR:
  835.         /* track cursor and display button info */
  836.         if (hwnd != hbutton_info) {
  837.             char buf[MAXSTR];
  838.             hbutton_info = hwnd;
  839.             load_string(GetWindowID(hwnd), buf, sizeof(buf));
  840.             hdc = BeginPaint(hwnd, &ps);
  841.             SetBkMode(hdc, TRANSPARENT);
  842.             if (info_rect.bottom) {
  843.                 GetClientRect(hwnd, &rect);
  844.                 rect.top = 0;
  845.                 rect.left = info_rect.left;
  846.                 rect.bottom = info_rect.bottom;
  847.                 FillRect(hdc, &rect, GetStockObject(LTGRAY_BRUSH));
  848.                 SelectPen(hdc, GetStockObject(BLACK_PEN));
  849.                 MoveTo(hdc, rect.left, rect.bottom);
  850.                 LineTo(hdc, rect.right, rect.bottom);
  851.             }
  852.             TextOut(hdc, info_file.x, info_file.y, buf, strlen(buf));
  853.             EndPaint(hwnd, &ps);
  854.         }
  855.         InvalidateRect(hwndimg, &info_rect, FALSE);
  856.         UpdateWindow(hwndimg);
  857.         break;
  858. #endif
  859.     }
  860.     return CallWindowProc(lpfnButtonWndProc, hwnd, message, wParam, lParam);
  861. }
  862.  
  863.  
  864. BOOL
  865. set_timer(UINT period)
  866. {
  867.     timeout_count = period;
  868.     bTimeout = FALSE;
  869.     if (SetTimer(hwndimg, ID_MYTIMER, 1000, NULL) != 0) {
  870.         bTimerSet = TRUE;
  871.         return TRUE;
  872.     }
  873.  
  874.     bTimerSet = FALSE;
  875.     gserror(IDS_NOTIMER, NULL, MB_ICONINFORMATION, SOUND_TIMEOUT);
  876.     return FALSE;
  877. }
  878.  
  879. void
  880. clear_timer()
  881. {
  882.     if (bTimerSet)
  883.         KillTimer(hwndimg, ID_MYTIMER);
  884.     bTimerSet = FALSE;
  885.     bTimeout = FALSE;
  886.     EnableWindow(hwndimg, TRUE);
  887. }
  888.  
  889.  
  890. /* remove temporary files etc. */
  891. void
  892. gsview_close()
  893. {
  894.     gs_close();
  895.     pipeclose();
  896.     print_cleanup();
  897.     if (page_list.select)
  898.         free(page_list.select);
  899.     page_list.select = NULL;
  900.     if (doc)
  901.         dsc_scan_clean(doc);
  902.     doc = (PSDOC *)NULL;
  903.     if (option.settings)
  904.         write_profile();
  905.     SetCursor(GetClassCursor((HWND)NULL));
  906.     return;
  907. }
  908.  
  909.  
  910. void
  911. copy_clipboard()
  912. {
  913.     if (hwndimgchild && IsWindow(hwndimgchild))
  914.         SendMessage(hwndimgchild, WM_GSVIEW, COPY_CLIPBOARD, NULL);
  915. }
  916.